package name.elftesting.rfbplayer;

import java.awt.*;
import java.awt.event.*;

class LWScrollPane extends Container implements AdjustmentListener {

	/** position info */
	private Point scrollPosition = new Point(0, 0);

	/** panel to hold component to scroll */
	private Panel innerPanel = new Panel() {

		public void update(Graphics g) {
			if (needClear) {
				super.update(g);
				needClear = false;
			} else
				this.paint(g);
		}

	};

	/** component to display */
	private Component containedComp;

	/** layout info */
	private GridBagLayout gb;
	private GridBagConstraints gbc;

	/** scroll bars */
	private Scrollbar xScroller;
	private Scrollbar yScroller;

	/** flags indicating which scollbars are visible */
	private boolean showingXScroll = false;
	private boolean showingYScroll = false;

	/** flag indicating when innerpanel needs to repaint background */
	private boolean needClear = false;

	/** dimensions for our preferred size */
	private int width = 0;
	private int height = 0;

	/** c'tor for a new scroll pane */
	public LWScrollPane() {
		// create scroll bars
		xScroller = new Scrollbar(Scrollbar.HORIZONTAL) {

			public boolean isFocusable() {
				return false;
			}

		};
		yScroller = new Scrollbar(Scrollbar.VERTICAL) {

			public boolean isFocusable() {
				return false;
			}

		};
		xScroller.addAdjustmentListener(this);
		yScroller.addAdjustmentListener(this);

		// layout info
		gb = new GridBagLayout();
		gbc = new GridBagConstraints();
		setLayout(gb);
		setBackground(Color.white);

		// added inner panel
		// innerPanel.setBackground(Color.blue);
		gbc.fill = GridBagConstraints.BOTH;
		gbc.gridx = 0;
		gbc.gridy = 0;
		gbc.weightx = 100;
		gbc.weighty = 100;
		gb.setConstraints(innerPanel, gbc);
		add(innerPanel);
		innerPanel.setLayout(null);
	}

	/*
	 * public void update(Graphics g) { paint(g); }
	 */
	/*
	 * public void paint(Graphics g) { super.paint(g); }
	 */

	/**
	 * Provided to allow the containing frame to resize. OS X JVM 1.3 would not
	 * allow a frame to be made smaller without overriding getMinimumSize.
	 */
	public Dimension getMinimumSize() {
		return new Dimension(0, 0);
	}

	public Dimension getPreferredSize() {
		return new Dimension(width, height);
	}

	public void setSize(int width, int height) {
		this.width = width;
		this.height = height;
		super.setSize(width, height);
	}

	public void setSize(Dimension d) {
		setSize(d.width, d.height);
	}

	/**
	 * Force component to clear itself before repainting. Primarily useful if
	 * the contained component shrinks without the scroll pane reducing in size.
	 */
	public void clearAndRepaint() {
		needClear = true;
		innerPanel.repaint();
	}

	/** Add the component to be scrolled by scroll pane */
	void addComp(Component comp) {
		containedComp = comp;
		innerPanel.add(containedComp);
	}

	/**
	 * Set the point of the component to display in the upper left corner of the
	 * viewport.
	 */
	void setScrollPosition(int x, int y) {
		Dimension vps = getViewportSize();
		Dimension ccs = containedComp.getPreferredSize();

		// skip entirely if component smaller than viewer
		if (ccs.width <= vps.width && ccs.height <= vps.height)
			return;

		// don't scroll too far left or up
		if (x < 0)
			x = 0;
		if (y < 0)
			y = 0;

		// don't scroll too far right or down
		if (ccs.width <= vps.width)
			x = 0;
		else if (x > (ccs.width - vps.width))
			x = ccs.width - vps.width;
		if (ccs.height <= vps.height)
			y = 0;
		else if (y > (ccs.height - vps.height))
			y = ccs.height - vps.height;

		scrollPosition = new Point(x, y);
		containedComp.setLocation(-scrollPosition.x, -scrollPosition.y);
		xScroller.setValue(scrollPosition.x);
		yScroller.setValue(scrollPosition.y);
	}

	/** Returns the point at the upper left corner of viewport */
	Point getScrollPosition() {
		return new Point(scrollPosition);
	}

	/** Return the dimensions of the viewport */
	public Dimension getViewportSize() {
		int vpW, vpH;
		Dimension size = getSize();
		vpW = size.width;
		vpH = size.height;
		if (showingYScroll)
			vpW -= yScroller.getSize().width;
		if (showingXScroll)
			vpH -= xScroller.getSize().height;

		return new Dimension(vpW, vpH);
	}

	/**
	 * Ensure that the scroll pane is properly arranged after a component is
	 * added, the pane is resized, etc.
	 */
	public void doLayout() {
		/** Add scroll bars as necessary */
		boolean needX = false, needY = false;
		Dimension innerSize = containedComp.getPreferredSize();
		Dimension scrollDimension = getSize();

		if (innerSize.width > scrollDimension.width)
			needX = true;
		if (innerSize.height > scrollDimension.height)
			needY = true;

		showingXScroll = false;
		showingYScroll = false;
		remove(yScroller);
		remove(xScroller);

		if (needY) {
			gbc.gridy = 0;
			gbc.gridx = 1;
			gbc.weightx = 0;
			gb.setConstraints(yScroller, gbc);
			add(yScroller);
			showingYScroll = true;
		}

		if (needX) {
			gbc.gridy = 1;
			gbc.gridx = 0;
			gbc.weightx = 100;
			gbc.weighty = 0;
			gb.setConstraints(xScroller, gbc);
			add(xScroller);
			showingXScroll = true;
		}

		/* set scroll bar values */
		int vpW, vpH;
		vpW = scrollDimension.width;
		vpH = scrollDimension.height;
		if (showingYScroll)
			vpW -= yScroller.getSize().width;
		if (showingXScroll)
			vpH -= xScroller.getSize().height;
		yScroller.setValues(0, vpH, 0, innerSize.height);
		xScroller.setValues(0, vpW, 0, innerSize.width);

		containedComp.setLocation(0, 0);
		super.doLayout();
	}

	/**
	 * Adjustment listener method for receiving callbacks from scroll actions.
	 * 
	 * @param e
	 *            the AdjustmentEvent
	 * @return void
	 */
	public void adjustmentValueChanged(AdjustmentEvent e) {
		Point p = containedComp.getLocation();
		if (e.getAdjustable() == xScroller) {
			p.x = -e.getValue();
			scrollPosition.x = e.getValue();
		} else {
			p.y = -e.getValue();
			scrollPosition.y = e.getValue();
		}
		containedComp.setLocation(p);
	}

}
